#pragma once

#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif

#include "util.hpp"
#include "sink.hpp"
#include "format.hpp"
#include "level.hpp"
#include "buffer.hpp"
#include "looper.hpp"
#include <atomic>
#include <mutex>
#include <cstdarg>
#include <unordered_map>
namespace logs
{
    // 抽象日志器基类
    // 派生出不同的子类（同步、异步）;
    class logger
    {
    public:
        using ptr = std::shared_ptr<logger>;
        logger(const std::string &logger_name, LogLevel::Value level, Formatter::ptr &formater, std::vector<LogSink::ptr> sinks)
            : _logger_name(logger_name), _limit_value(level), _formater(formater), _sinks(sinks.begin(), sinks.end())
        {
        }
        const std::string &name()
        {
            return _logger_name;
        }
        // 完成日志消息的构建，根据传入的格式化字符串，及参数，格式化输出日志消息；
        void debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 传入参数，构建日志消息对象， 对日志消息进行格式化等到日志字符串--然后进行输出

            // 1. 判断日志等级，是否可以输出
            if (LogLevel::Value::DEBUG < _limit_value)
                return;
            // 2. 根据fmt格式化参数和不定参，构建出日志消息字符串（有效消息）
            // 使用不定参函数
            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
                std::cout << "vasprintf failed !" << std::endl;
            va_end(ap);
            Serialize(LogLevel::Value::DEBUG, file, line, res); // 防止代码过多的冗余，封装一些功能
            free(res);                                          // 最后记得释放res的空间
        }
        void info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::Value::INFO < _limit_value)
                return;

            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
                std::cout << "vasprintf failed !" << std::endl;
            va_end(ap);
            Serialize(LogLevel::Value::INFO, file, line, res); // 防止代码过多的冗余，封装一些功能
            free(res);
        }
        void warn(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::Value::WARN < _limit_value)
                return;

            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
                std::cout << "vasprintf failed !" << std::endl;
            va_end(ap);
            Serialize(LogLevel::Value::WARN, file, line, res); // 防止代码过多的冗余，封装一些功能
            free(res);
        }
        void error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::Value::ERROR < _limit_value)
                return;

            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
                std::cout << "vasprintf failed !" << std::endl;
            va_end(ap);
            Serialize(LogLevel::Value::ERROR, file, line, res); // 防止代码过多的冗余，封装一些功能
            free(res);
        }
        void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            if (LogLevel::Value::FATAL < _limit_value)
                return;

            va_list ap;
            va_start(ap, fmt);
            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
                std::cout << "vasprintf failed !" << std::endl;
            va_end(ap);
            Serialize(LogLevel::Value::FATAL, file, line, res); // 防止代码过多的冗余，封装一些功能
            free(res);
        }

    protected:
        void Serialize(LogLevel::Value val, const std::string &file, size_t line, const char *data)
        {
            // 3.构建日志消息对象
            logMsg msg(val, line, file, data, _logger_name);
            // 4.通过格式化工具对logmsg进行格式化，得到格式化后的完整日志字符串
            std::string s;
            s = _formater->format(msg);
            // 5.日志输出落地
            log(s.c_str(), s.size());
        }
        // 负责实际的落地输出
        virtual void log(const char *data, size_t len) = 0;

    protected:
        std::mutex _mtx;
        std::string _logger_name;
        std::atomic<LogLevel::Value> _limit_value;
        Formatter::ptr _formater;
        std::vector<LogSink::ptr> _sinks; // 存在多个落地方向
    };
    class SyncLogger : public logger
    {
    public:
        SyncLogger(const std::string &logger_name, LogLevel::Value level, Formatter::ptr &formater, std::vector<LogSink::ptr> sinks)
            : logger(logger_name, level, formater, sinks)
        {
        }

    protected:
        void log(const char *data, size_t len) override
        {
            std::unique_lock<std::mutex> lock(_mtx);
            for (auto &sink : _sinks)
            {
                sink->log(data, len);
            }
        }
    };

    class AsyncLogger : public logger
    {
    public:
        AsyncLogger(const std::string &logger_name, LogLevel::Value level,
                    Formatter::ptr &formater, std::vector<LogSink::ptr> &sinks, AsyncType looper_type)
            : logger(logger_name, level, formater, sinks),
              _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realSink, this, std::placeholders::_1), looper_type)) {}

    protected:
        // 将缓冲区中的数据进行落地(将数据写入到缓冲区)
        void log(const char *data, size_t len) override
        {
            _looper->push(data, len);
        }
        // 从缓冲区中拿数据, 传入到_looper中的回调函数
        void realSink(Buffer &_buffer)
        {
            if (_sinks.empty())
                return;
            for (auto &sink : _sinks)
            {
                sink->log(_buffer.begin(), _buffer.able_read_size());
            }
        }

    private:
        AsyncLooper::ptr _looper;
    };

    enum class LoggerType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };
    // 使用建造者模式构建日志器；简化构建复杂度
    // 抽象建筑者类
    class LoggerBuilder
    {
    public:
        LoggerBuilder() : _logger_type(LoggerType::LOGGER_SYNC),
                          _limit_value(LogLevel::Value::DEBUG),
                          _looper_type(AsyncType::ASYNC_SAFE)
        {
        }
        void BuilderLoggerType(LoggerType type) { _logger_type = type; }
        void BuilderLoggerName(const std::string &name) { _logger_name = name; }
        void BuilderLoggerLevel(LogLevel::Value level) { _limit_value = level; }
        void BuilderEnableUnsafeAsync() { _looper_type = AsyncType::ASYNC_UNSAFE; }
        void BuilderLoggerFormatter(const std::string &pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }
        template <typename SinkType, typename... Args>
        void buildSink(Args &&...args)
        {
            LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }
        virtual logger::ptr build() = 0;

    protected:
        AsyncType _looper_type;
        LoggerType _logger_type;
        std::string _logger_name;
        std::atomic<LogLevel::Value> _limit_value;
        Formatter::ptr _formatter;
        std::vector<LogSink::ptr> _sinks;
    };
    // 本地日志器构建类，还可以扩展远端日志器构建类
    class localLoggerBuild : public LoggerBuilder
    {
    public:
        logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if (_formatter == nullptr)
            {
                _formatter = _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                buildSink<StdoutSink>();
            }
            if (_logger_type == LoggerType::LOGGER_ASYNC)
            {
                return std::make_shared<AsyncLogger>(_logger_name, _limit_value, _formatter, _sinks, _looper_type);
            }
            return std::make_shared<SyncLogger>(_logger_name, _limit_value, _formatter, _sinks);
        }
    };

    class LoggerManager
    {
    public:
        static LoggerManager &getInstance()
        {
            static LoggerManager logger_manager;
            return logger_manager;
        }

        void add_Logger(logger::ptr &logger)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            _loggers.insert({logger->name(), logger});
        }
        bool has_Logger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
                return false;
            return true;
        }
        logger::ptr get_Logger(const std::string &name)
        {
            std::unique_lock<std::mutex> lock(_mtx);
            auto it = _loggers.find(name);
            if (it == _loggers.end())
                return logger::ptr();
            return it->second;
        }
        logger::ptr &root_Logger()
        {
            return _root_logger;
        }

    private:
        LoggerManager()
        {
            std::unique_ptr<logs::LoggerBuilder> builder = std::make_unique<logs::localLoggerBuild>();
            // 默认同步日志器
            // 标准输出
            // 输出等级debug
            // 日志器模式：安全模式
            // 默认输出类型：[%d{%H:%M:%S}][%t][%c][%f:%l][%p] %m%n
            // 示例：[11:13:41][139758309214016][root][main.cc:22][DEBUG] 日志器测试...
            builder->BuilderLoggerName("root");

            builder->buildSink<logs::StdoutSink>();
            _root_logger = builder->build();
            _loggers.insert({"root", _root_logger});
        }

    private:
        std::mutex _mtx;
        logger::ptr _root_logger; // 默认日志器
        std::unordered_map<std::string, logger::ptr> _loggers;
    };
    class GlobalLoggerBuild : public LoggerBuilder
    {
    public:
        logger::ptr build() override
        {
            assert(!_logger_name.empty());
            if (_formatter == nullptr)
            {
                _formatter = _formatter = std::make_shared<Formatter>();
            }
            if (_sinks.empty())
            {
                buildSink<StdoutSink>();
            }
            logger::ptr logger;
            if (_logger_type == LoggerType::LOGGER_ASYNC){
                logger = std::make_shared<AsyncLogger>(_logger_name, _limit_value, _formatter, _sinks, _looper_type);
            }
            else logger = std::make_shared<SyncLogger>(_logger_name, _limit_value, _formatter, _sinks);
            LoggerManager::getInstance().add_Logger(logger);
            return logger;
        }
    };
}